﻿using System;

namespace LAPI.Business.Gestores
{
    /// <summary>
    /// Clase que implementa funciones para gestionar operaciones sobre la entidad de base de datos 'Reservas'
    /// </summary>
    public class GestorReservas
    {
        /// <summary>
        /// Logger de la clase
        /// </summary>
        private LAPI.Core.Logging.ILogger logger;

        /// <summary>
        /// Constructor
        /// </summary>
        public GestorReservas()
        {
            logger = LAPI.Core.Logging.LoggerFactory.CreateLogger(type: typeof(GestorReservas));
        }

        #region Getter     

        /// <summary>
        /// Método para filtrar una busqueda de reservas personales
        /// <ul>
        /// <li>deporte</li>
        /// <li>pista</li>
        /// <li>centro deportivo</li>
        /// <li>fecha reserva</li>
        /// </ul>
        /// </summary>
        /// <param name="filtroBusqueda">Diccionario con el filtro de la búsqueda</param>
        /// <param name="idUsuario">Identificador único del usuario</param>
        /// <returns>Una colección del modelo con todas las reservas</returns>
        /// <seealso cref="Reserva"/>
        /// <seealso cref="GestorBBDD"/>
        public System.Collections.Generic.List<LAPI.Data.Model.Reserva> ObtenerBusqueda(System.Collections.Hashtable filtroBusqueda, Int32 idUsuario)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            System.Collections.Generic.List<LAPI.Data.Model.Reserva> result;

            sql.Append("Select ");
            sql.Append(LAPI.Data.Model.Reserva.Columns);
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Reserva.Tables);
            sql.Append(" where usuario.id_usuario = reservas.id_usuario");
            sql.Append("   and deportespista.id_deportespista = reservas.id_deportespista");
            sql.Append("   and deportespista.id_deportes = deportes.id_deportes");
            sql.Append("   and deportespista.id_pista = pista.id_pista");
            sql.Append("   and pista.id_centrodeportivo = centrodeportivo.id_centrodeportivo");
            sql.Append("   and reservas.id_usuario = " + idUsuario);
            sql.Append("   and reservas.activo = 1 ");

            //Añadimos filtros
            if (filtroBusqueda.ContainsKey("centro"))
                sql.Append(" and centrodeportivo.descripcion like '%" + filtroBusqueda["centro"].ToString().Replace('*', '%') + "%'");
            if (filtroBusqueda.ContainsKey("deporte"))
                sql.Append(" and deportes.descripcion like '%" + filtroBusqueda["deporte"].ToString().Replace('*', '%') + "%'");
            if (filtroBusqueda.ContainsKey("pista"))
                sql.Append(" and pista.descripcion like '%" + filtroBusqueda["pista"].ToString().Replace('*', '%') + "%'");
            if (filtroBusqueda.ContainsKey("fecha"))
                sql.Append(" and reservas.hora_ini like '%" + filtroBusqueda["fecha"].ToString().Replace('*', '%') + "%'");

            sql.Append(" order by reservas.hora_ini desc ");

            try
            {
                oBBDD.Abrir();
                result = LAPI.Data.Model.Reserva.toModel(oBBDD.Select(sql.ToString()));
                oBBDD.CerrarParcial();
                return result;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return null;
            }
        }

        /// <summary>
        /// Método para filtrar una busqueda de reservas de una pista
        /// <ul>
        /// <li>deporte</li>
        /// <li>fecha reserva</li>
        /// </ul>
        /// </summary>
        /// <param name="filtroBusqueda">Diccionario con el filtro de la búsqueda</param>
        /// <param name="idPista">Identificador único de la pista</param>
        /// <returns>Una colección del modelo con todas las reservas</returns>
        /// <seealso cref="Reserva"/>
        /// <seealso cref="GestorBBDD"/>
        public System.Collections.Generic.List<LAPI.Data.Model.Reserva> ObtenerBusquedaPorPista(System.Collections.Hashtable filtroBusqueda, Int32 idPista)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            System.Collections.Generic.List<LAPI.Data.Model.Reserva> result;

            sql.Append("Select ");
            sql.Append(LAPI.Data.Model.Reserva.Columns);
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Reserva.Tables);
            sql.Append(" where usuario.id_usuario = reservas.id_usuario");
            sql.Append("   and deportespista.id_deportespista = reservas.id_deportespista");
            sql.Append("   and deportespista.id_deportes = deportes.id_deportes");
            sql.Append("   and deportespista.id_pista = pista.id_pista");
            sql.Append("   and pista.id_centrodeportivo = centrodeportivo.id_centrodeportivo");
            sql.Append("   and pista.id_pista = " + idPista);
            sql.Append("   and reservas.activo = 1 ");

            //Añadimos filtros
            if (filtroBusqueda.ContainsKey("deporte"))
                sql.Append(" and deportes.descripcion like '%" + filtroBusqueda["deporte"].ToString().Replace('*', '%') + "%'");
            if (filtroBusqueda.ContainsKey("fecha"))
                sql.Append(" and reservas.hora_ini like '%" + filtroBusqueda["fecha"].ToString().Replace('*', '%') + "%'");

            sql.Append(" order by reservas.hora_ini desc ");

            try
            {
                oBBDD.Abrir();
                result = LAPI.Data.Model.Reserva.toModel(oBBDD.Select(sql.ToString()));
                oBBDD.CerrarParcial();
                return result;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return null;
            }
        }

        /// <summary>
        /// Método para obtener las reservas de una persona
        /// </summary>
        /// <param name="idUsuario">Identificador único del usuario</param>
        /// <returns>Una colección del modelo con todas las reservas</returns>
        /// <seealso cref="Reserva"/>
        /// <seealso cref="GestorBBDD"/>
        public System.Collections.Generic.List<LAPI.Data.Model.Reserva> ObtenerPorUsuario(Int32 idUsuario)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            System.Collections.Generic.List<LAPI.Data.Model.Reserva> result;

            sql.Append("Select ");
            sql.Append(LAPI.Data.Model.Reserva.Columns);
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Reserva.Tables);
            sql.Append(" where usuario.id_usuario = reservas.id_usuario");
            sql.Append("   and deportespista.id_deportespista = reservas.id_deportespista");
            sql.Append("   and deportespista.id_deportes = deportes.id_deportes");
            sql.Append("   and deportespista.id_pista = pista.id_pista");
            sql.Append("   and pista.id_centrodeportivo = centrodeportivo.id_centrodeportivo");
            sql.Append("   and reservas.id_usuario = " + idUsuario);
            sql.Append("   and reservas.activo = 1 ");
            sql.Append(" order by reservas.hora_ini desc ");
        
            try
            {
                oBBDD.Abrir();
                result = LAPI.Data.Model.Reserva.toModel(oBBDD.Select(sql.ToString()));
                oBBDD.CerrarParcial();
                return result;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return null;
            }
        }

        /// <summary>
        /// Método para obtener las reservas de una pista
        /// </summary>
        /// <param name="idPista">Identificador único de la pista</param>
        /// <returns>Una colección del modelo con todas las reservas</returns>
        /// <seealso cref="Reserva"/>
        /// <seealso cref="GestorBBDD"/>
        public System.Collections.Generic.List<LAPI.Data.Model.Reserva> ObtenerPorPista(Int32 idPista)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            System.Collections.Generic.List<LAPI.Data.Model.Reserva> result;

            sql.Append("Select ");
            sql.Append(LAPI.Data.Model.Reserva.Columns);
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Reserva.Tables);
            sql.Append(" where usuario.id_usuario = reservas.id_usuario");
            sql.Append("   and deportespista.id_deportespista = reservas.id_deportespista");
            sql.Append("   and deportespista.id_deportes = deportes.id_deportes");
            sql.Append("   and deportespista.id_pista = pista.id_pista");
            sql.Append("   and pista.id_centrodeportivo = centrodeportivo.id_centrodeportivo");
            sql.Append("   and pista.id_pista = " + idPista);
            sql.Append("   and reservas.activo = 1 ");
            sql.Append(" order by reservas.hora_ini desc ");

            try
            {
                oBBDD.Abrir();
                result = LAPI.Data.Model.Reserva.toModel(oBBDD.Select(sql.ToString()));
                oBBDD.CerrarParcial();
                return result;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return null;
            }
        }

        /// <summary>
        /// Método para obtener las reservas de un deporte para una pista
        /// </summary>
        /// <param name="idPista">Identificador único de la pista</param>
        /// <param name="idCentro">Identificador único del centro deportivo</param>
        /// <param name="idDeporte">Identificador único del deporte</param>
        /// <returns>Una colección del modelo con todas las reservas</returns>
        /// <seealso cref="Reserva"/>
        /// <seealso cref="GestorBBDD"/>
        public System.Collections.Generic.List<LAPI.Data.Model.Reserva> ObtenerReservas(Int32 idPista, Int32 idCentro, Int32 idDeporte)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            System.Collections.Generic.List<LAPI.Data.Model.Reserva> result;

            sql.Append("Select ");
            sql.Append(LAPI.Data.Model.Reserva.Columns);
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Reserva.Tables);
            sql.Append(" where usuario.id_usuario = reservas.id_usuario");
            sql.Append("   and deportespista.id_deportespista = reservas.id_deportespista");
            sql.Append("   and deportespista.id_deportes = deportes.id_deportes");
            sql.Append("   and deportespista.id_pista = pista.id_pista");
            sql.Append("   and pista.id_centrodeportivo = centrodeportivo.id_centrodeportivo");
            sql.Append("   and pista.id_pista = " + idPista);
            sql.Append("   and centrodeportivo.id_centrodeportivo = " + idCentro);
            //sql.Append("   and deportes.id_deportes = " + idDeporte); --> no se filtra por deporte, porque pude haber más de un deporte por pista
            sql.Append("   and reservas.activo = 1 ");
            sql.Append("   and reservas.hora_ini >= curdate()");
            sql.Append(" order by reservas.hora_ini desc ");

            try
            {
                oBBDD.Abrir();
                result = LAPI.Data.Model.Reserva.toModel(oBBDD.Select(sql.ToString()));
                oBBDD.CerrarParcial();
                return result;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return null;
            }
        }

        /// <summary>
        /// Método para obtener las reservas de un deporte para una pista
        /// </summary>
        /// <param name="idPista">Identificador único de la pista</param>
        /// <param name="idCentro">Identificador único del centro deportivo</param>
        /// <param name="idDeporte">Identificador único del deporte</param>
        /// <returns>Una colección del modelo con todas las reservas</returns>
        /// <seealso cref="Reserva"/>
        /// <seealso cref="GestorBBDD"/>
        public System.Collections.Hashtable ObtenerPrecio(Int32 idPista, Int32 idCentro, Int32 idDeporte)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            System.Collections.Hashtable result = new System.Collections.Hashtable();

            sql.Append("Select ");
            sql.Append(" pista.luz luz, deportespista.precio, deportespista.suplementoluz");
            sql.Append(" from DEPORTESPISTA, DEPORTES, PISTA ");
            sql.Append(" where deportespista.id_pista = pista.id_pista");
            sql.Append("   and pista.id_pista = " + idPista);
            sql.Append("   and pista.id_centrodeportivo = " + idCentro);
            sql.Append("   and deportespista.id_deportes = deportes.id_deportes");
            sql.Append("   and deportes.id_deportes = " + idDeporte);

            try
            {
                oBBDD.Abrir();
                var datos = oBBDD.Select(sql.ToString());
                oBBDD.CerrarParcial();

                result.Add("luz",datos.Tables[0].Rows[0]["luz"]);
                result.Add("precio",datos.Tables[0].Rows[0]["precio"]);
                result.Add("suplementoluz", datos.Tables[0].Rows[0]["suplementoluz"]);
                return result;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return null;
            }
        }
    #endregion

        #region Comprobaciones

        /// <summary>
        /// Método para comprobar si existe ya una reserva para una pista en un intervalo 
        /// </summary>
        /// <param name="datosReserva">Modelo con los datos de reserva a validar</param>
        /// <param name="idPista">Identificador único de la pista</param>
        /// <returns>True si no existe ninguna. False si ocurre lo contrario</returns>
        /// <seealso cref="Reserva"/>
        /// <seealso cref="GestorBBDD"/>
        public Boolean ComprobarPeriodoReserva(LAPI.Data.Model.Reserva datosReserva, Int32 idPista)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();

            sql.Append("Select 1");
            sql.Append(" from ");
            sql.Append(LAPI.Data.Model.Reserva.Tables);
            sql.Append(" where usuario.id_usuario = reservas.id_usuario");
            sql.Append("   and deportespista.id_deportespista = reservas.id_deportespista");
            sql.Append("   and deportespista.id_deportes = deportes.id_deportes");
            sql.Append("   and deportespista.id_pista = pista.id_pista");
            sql.Append("   and pista.id_centrodeportivo = centrodeportivo.id_centrodeportivo");
            sql.Append("   and pista.id_pista = " + idPista);
            sql.Append("   and reservas.hora_ini = '" + datosReserva.horaInicio.ToString("yyy-MM-dd hh:mm"));
            sql.Append("'   and reservas.activo = 1 ");

            try
            {
                oBBDD.Abrir();
                var result = oBBDD.Select(sql.ToString());
                oBBDD.CerrarParcial();

                if (result.Tables[0].Rows.Count > 0)
                    return false;
                return true;
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                return false;
            }
        }

        #endregion

        #region insert

        /// <summary>
        /// Método para insertar una nueva reserva en la base de datos
        /// </summary>
        /// <param name="datosReserva">Modelo con los datos de la reserva a insertar (previamente validados)</param>
        /// <seealso cref="Reserva"/>
        /// <seealso cref="GestorBBDD"/>
        public void Insertar(LAPI.Data.Model.Reserva datosReserva)
        {
            System.Text.StringBuilder sql = new System.Text.StringBuilder();
            LAPI.Data.GestorBBDD oBBDD = LAPI.Data.GestorBBDDFactory.getGestorBBDD();
            Int32 result;

            sql.Append("Insert into ");
            sql.Append(LAPI.Data.Model.Reserva.Table);
            sql.Append(" ( ");
            sql.Append(datosReserva.ToInsertColumns());
            sql.Append(" ) values ( ");
            sql.Append(datosReserva.ToInsertValues());
            sql.Append(" ) ");            

            try
            {
                oBBDD.Abrir();
                result = oBBDD.Insert(sql.ToString());               
                oBBDD.CerrarParcial();
                if (result != 1)
                    throw new Exception("No se ha insertado el registro: " + datosReserva);
            }
            catch (Exception ex)
            {
                oBBDD.Cerrar();
                logger.Error(message: ex.Message, exception: ex);
                throw new Exception("No se ha insertado el registro: " + datosReserva);
            }           
        }

        #endregion
    }
}
